package com.songlanyun.modules.servicegoods.service.impl;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.songlanyun.common.enums.GoodsConstant;
import com.songlanyun.common.exception.RRException;
import com.songlanyun.common.utils.BeanUtil;
import com.songlanyun.common.utils.MapTools;
import com.songlanyun.common.utils.custom.ClassConvertUtils;
import com.songlanyun.common.utils.custom.MathUtils;
import com.songlanyun.common.validator.ValidatorUtils;
import com.songlanyun.modules.cnarea.entity.CnArea;
import com.songlanyun.modules.cnarea.service.CnAreaService;
import com.songlanyun.modules.exception.GoodsExceptionEnum;
import com.songlanyun.modules.exception.ServiceGoodsExceptionEnum;
import com.songlanyun.modules.goods.model.dto.GoodsStatusDTO;
import com.songlanyun.modules.goods.model.vo.GoodsPageReq;
import com.songlanyun.modules.goods.model.vo.GoodsSlimVo;
import com.songlanyun.modules.group.entity.ProductGoodsGroupEntity;
import com.songlanyun.modules.servicegoods.entity.*;
import com.songlanyun.modules.servicegoods.model.dto.ServiceGoodsDTO;
import com.songlanyun.modules.servicegoods.model.dto.ServiceItemDTO;
import com.songlanyun.modules.servicegoods.model.vo.NearbyShopSlimVo;
import com.songlanyun.modules.servicegoods.model.vo.ServiceGoodsPageReq;
import com.songlanyun.modules.servicegoods.model.vo.ServiceGoodsSlimVo;
import com.songlanyun.modules.servicegoods.service.*;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.songlanyun.common.utils.PageUtils;
import com.songlanyun.common.utils.Query;

import com.songlanyun.modules.servicegoods.dao.ServiceGoodsDao;
import org.springframework.transaction.annotation.Transactional;
import sun.nio.ch.ThreadPool;


@Service("serviceGoodsService")
public class ServiceGoodsServiceImpl extends ServiceImpl<ServiceGoodsDao, ServiceGoods> implements ServiceGoodsService {

    @Autowired
    private ServiceGoodsContentService serviceGoodsContentService;

    @Autowired
    private ServiceGoodsGroupRelationService serviceGoodsGroupRelationService;

    @Autowired
    private ServiceGoodsGroupService serviceGoodsGroupService;

    @Autowired
    private ServiceItemService serviceItemService;

    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;

    @Autowired
    private CnAreaService cnAreaService;


    @Override
    public ServiceGoods create(ServiceGoods entity) {
        ValidatorUtils.validateEntity(entity);
        if (entity.getMarketPrice().compareTo(entity.getSalePrice()) <= 0) {
            throw new RRException(GoodsExceptionEnum.SERVICE_MARKET_PRICE_HEIGHT);
        }

        this.baseMapper.insert(entity);
        return entity;
    }

    @Override
    public ServiceGoods modify(ServiceGoods entity) {
        ValidatorUtils.validateEntity(entity);
        if (entity.getMarketPrice().compareTo(entity.getSalePrice()) <= 0) {
            throw new RRException(GoodsExceptionEnum.MARKET_PRICE_HEIGHT);
        }
        this.baseMapper.updateById(entity);
        return entity;
    }

    @Override
    public void remove(Long id) {
        this.removeById(id);
    }

    /**
     * 添加服务商品
     *
     * @param shopId
     * @param dto
     * @return
     */
    @Transactional
    @Override
    public ServiceGoods add(Long shopId, ServiceGoodsDTO dto) {
        ServiceGoods goods = new ServiceGoods();
        if (dto.getServiceItems().size() > 0) {
            BigDecimal sumV = dto.getServiceItems().stream().map(ServiceItemDTO::getItemPrice).reduce(BigDecimal.ZERO, BigDecimal::add);
            dto.setMarketPrice(sumV.setScale(2, BigDecimal.ROUND_HALF_UP));
        }
        BeanUtil.copyPropertiesIgnoreNull(dto, goods);
        goods.setShopId(shopId);
        goods.computeResultSaleNum();
        goods = this.create(goods);

        breachSaveGroups(shopId, goods.getId(), dto);
        breachSaveItems(goods.getId(), dto);

        serviceGoodsContentService.setContent(goods.getId(), dto.getMobileDetail());
        goods.loadGroupList();
        return goods;
    }

    /**
     * 修改服务商品
     *
     * @param shopId
     * @param dto
     * @return
     */
    @Transactional
    @Override
    public ServiceGoods update(Long shopId, ServiceGoodsDTO dto) {
        ServiceGoods goods = this.loadServiceGoodsByShopIdAndId(shopId, dto.getId(), true);
        BeanUtil.copyPropertiesIgnoreNull(dto, goods);
        goods = this.modify(goods);

        breachSaveGroups(shopId, goods.getId(), dto);
        breachSaveItems(goods.getId(), dto);

        serviceGoodsContentService.setContent(goods.getId(), dto.getMobileDetail());
        goods.loadGroupList();

        return goods;
    }


    private void breachSaveItems(Long goodsId, ServiceGoodsDTO dto) {
        List<ServiceItem> collect = dto.getServiceItems().stream().map((itemDTO -> {
            ServiceItem serviceItem = new ServiceItem();
            serviceItem.setServiceGoodsId(goodsId);
            serviceItem.setItemName(itemDTO.getItemName());
            serviceItem.setItemPrice(itemDTO.getItemPrice());
            serviceItem.setNum(itemDTO.getNum());
            return serviceItem;
        })).collect(Collectors.toList());

        serviceItemService.branchCreate(goodsId, collect);
    }


    private void breachSaveGroups(Long shopId, Long goodsId, ServiceGoodsDTO dto) {
        List<ServiceGoodsGroupRelation> relationList = new ArrayList<>();
        dto.getGroupIds().forEach((groupId) -> {
            ServiceGoodsGroup group = serviceGoodsGroupService.getByShopIdAndId(shopId, groupId);
            if (group == null) {
                throw new RRException(ServiceGoodsExceptionEnum.SERVICE_GROUP_NOT_EXISTS);
            }
            ServiceGoodsGroupRelation relation = new ServiceGoodsGroupRelation();
            relation.setServiceGoodsId(goodsId);
            relation.setGoodsGroupId(groupId);

            relationList.add(relation);
        });
        serviceGoodsGroupRelationService.breachSave(goodsId, relationList);
    }

    /**
     * 根据店实id和服务商品id查询
     *
     * @param shopId
     * @param id
     * @param tw
     * @return
     */
    @Override
    public ServiceGoods loadServiceGoodsByShopIdAndId(Long shopId, Long id, Boolean tw) {

        ServiceGoods goods = this.getOne(new LambdaQueryWrapper<ServiceGoods>()
                .eq(ServiceGoods::getId, id)
                .eq(ServiceGoods::getShopId, shopId));
        if (goods == null && tw) {
            throw new RRException(ServiceGoodsExceptionEnum.SERVICE_GOODS_NOT_EXISTS);
        }
        return goods;
    }

    /**
     * @param id
     * @param tw
     * @return
     */
    @Override
    public ServiceGoods loadServiceGoodsById(Long id, Boolean tw) {
        ServiceGoods goods = this.getById(id);
        if (goods == null && tw) {
            throw new RRException(ServiceGoodsExceptionEnum.SERVICE_GOODS_NOT_EXISTS);
        }
        return goods;
    }

    @Transactional
    @Override
    public void delete(Long shopId, Long id) {
        this.loadServiceGoodsByShopIdAndId(shopId, id, true);
        this.remove(id);
    }

    /**
     * 商家上架下架商品理员
     *
     * @param shopId
     * @param dto
     */
    @Transactional
    @Override
    public void added(Long shopId, GoodsStatusDTO dto) {
        ServiceGoods serviceGoods = this.loadServiceGoodsByShopIdAndId(shopId, dto.getGoodsId(), true);
        serviceGoods.setAdded(dto.getAdded());
        this.modify(serviceGoods);
    }

    /**
     * 商家设置服务商品是否是热门
     */
    @Transactional
    @Override
    public void hot(Long shopId, GoodsStatusDTO dto) {
        ServiceGoods serviceGoods = this.loadServiceGoodsByShopIdAndId(shopId, dto.getGoodsId(), true);
        serviceGoods.setHot(dto.getHot());
        this.modify(serviceGoods);
    }

    /**
     * 商家设置服务商品是否是新品
     */
    @Transactional
    @Override
    public void newGoods(Long shopId, GoodsStatusDTO dto) {
        ServiceGoods serviceGoods = this.loadServiceGoodsByShopIdAndId(shopId, dto.getGoodsId(), true);
        serviceGoods.setNewGoods(dto.getNewGoods());
        this.modify(serviceGoods);
    }

    /**
     * 商家设置服务商品是否是推荐
     */
    @Transactional
    @Override
    public void recommend(Long shopId, GoodsStatusDTO dto) {
        ServiceGoods serviceGoods = this.loadServiceGoodsByShopIdAndId(shopId, dto.getGoodsId(), true);
        serviceGoods.setRecommend(dto.getRecommend());
        this.modify(serviceGoods);
    }

    /**
     * 平台管理员审核
     */
    @Transactional
    @Override
    public void check(Long goodsId, GoodsStatusDTO dto) {
        ServiceGoods serviceGoods = this.loadServiceGoodsById(goodsId, true);
        serviceGoods.setVerifyStatus(GoodsConstant.VerifyStatus.getByCode(dto.getVerifyStatus()));
        serviceGoods.setVerifyRemark(dto.getRemark());
        serviceGoods.setLastVerifyTime(new Date());
        if (GoodsConstant.VerifyStatus.NO.equals(serviceGoods.getVerifyStatus())) {
            serviceGoods.setAdded(false);
        }
        this.modify(serviceGoods);
    }

    /**
     * 平台查询所有服务商品（为了审核）
     * * params参数说明
     * * shop_id 商家店铺id可以不给不给查所有
     * * shop_name 商家店铺名乐可以不给不给查所有
     * * verify_status 审核状态 可以不给查全部 有效值：（0待审，1通过，2不通过）
     * * title 标题（可以不给，用来模糊查询）
     * * page 当前第几页（默认第一页）
     * * limit 每页多少条 （默认每页10条）
     */
    @Override
    public PageUtils queryALLPage(Map<String, Object> params) {
        IPage<ServiceGoodsSlimVo> goodsSlimVoIPage = this.baseMapper.queryAllPage(new Query<ServiceGoodsSlimVo>().getPage(params), paramsMapToReq(params));
        return new PageUtils(goodsSlimVoIPage);

    }

    /**
     * 商家查询所有服务商品
     * * params参数说明
     * * shop_id 商家店铺id可以不给不给查所有
     * * verify_status 审核状态 可以不给查全部 有效值：（0待审，1通过，2不通过）
     * * group_id 商家分组
     * * added 上下架
     * * title 标题（可以不给，用来模糊查询）
     * * page 当前第几页（默认第一页）
     * * limit 每页多少条 （默认每页10条）
     */
    @Override
    public PageUtils querySelfPage(Map<String, Object> params) {
        IPage<ServiceGoodsSlimVo> goodsSlimVoIPage = this.baseMapper.querySelfPage(new Query<ServiceGoodsSlimVo>().getPage(params), paramsMapToReq(params));
        return new PageUtils(goodsSlimVoIPage);
    }

    /**
     * 在商家店铺中显示推荐，热门，新品，自营商品
     * type = recommend，hot,new
     * limit= 数量
     *
     * @param params
     * @return
     */
    @Override
    public List<ServiceGoodsSlimVo> loadList(Map<String, Object> params) {
        return this.baseMapper.loadList(paramsMapToReq(params));
    }

    @Override
    public Integer loadCount(Map<String, Object> params) {
        return this.baseMapper.loadCount(paramsMapToReq(params));
    }

    @Override
    public List<NearbyShopSlimVo> nearbyShopList(Map<String, Object> params) {

        List<NearbyShopSlimVo> shops = new ArrayList<>();
        final String lon = MapUtil.getStr(params, "lon");
        final String lat = MapUtil.getStr(params, "lat");

        String areaCode = MapUtil.getStr(params, "area_code");
        String address = MapUtil.getStr(params, "address");
        if(StringUtils.isEmpty(areaCode) && StringUtils.isNotEmpty(address))
        {
            JSONObject result = cnAreaService.getCode(address);
            JSONObject adInfo = result.getJSONObject("ad_info");
            params.put("area_code",adInfo.getString("adcode"));
        }

        // TODO 新版上线前的测试，要求无论选择哪个地区，都查询出全部同城商家，
        // TODO 只能临时清除参数：area_code
        params.put("area_code", null);

        //查询店铺
        CompletableFuture<List<NearbyShopSlimVo>> infoFuture = CompletableFuture.supplyAsync(() -> {
            List<NearbyShopSlimVo> list = this.baseMapper.nearbyShopList(paramsMapToReq(params));
            shops.addAll(list);
            return list;
        }, threadPoolExecutor);


        //根据店铺的数据查距离
        CompletableFuture<Void> distanceProcessFuture = infoFuture.thenAcceptAsync(result -> {
            result.forEach(shop -> {
                if (StringUtils.isNotEmpty(lon) && StringUtils.isNotEmpty(lat)) {
                    //计算经纬度距离
                    double calculate = MapTools.calculate(lon, lat, shop.getTxLongitude(), shop.getTxLatitude());
                    shop.setDistance(calculate);
                }
            });
        }, threadPoolExecutor);


//        //根据店铺的数据查服务商品
//        CompletableFuture<Void> serviceGoodsLoadFuture = infoFuture.thenAcceptAsync(result -> {
//            result.forEach(shop -> {
//                ServiceGoodsPageReq serviceGoodsPageReq = new ServiceGoodsPageReq();
//                serviceGoodsPageReq.setLimit(2);
//                serviceGoodsPageReq.setShopId(shop.getShopId());
//
//                if (params.get("category_id") != null) {
//                    serviceGoodsPageReq.setServiceCategoryId(ClassConvertUtils.objToLong(params.get("category_id")));
//                }
//
//                if (params.get("title") != null && StringUtils.isNotBlank(params.get("title").toString())) {
//                    serviceGoodsPageReq.setTitle(params.get("title").toString());
//                }
//                List<ServiceGoodsSlimVo> goodsSlimVos = this.baseMapper.loadList(serviceGoodsPageReq);
//                shop.setList(goodsSlimVos);
//            });
//
//        }, threadPoolExecutor);
//
//        //根据店铺的数据查服务商品数量
//        CompletableFuture<Void> serviceGoodsCountLoadFuture = infoFuture.thenAcceptAsync(result -> {
//            result.forEach(shop -> {
//                ServiceGoodsPageReq serviceGoodsPageReq = new ServiceGoodsPageReq();
//                serviceGoodsPageReq.setShopId(shop.getShopId());
//                if (params.get("category_id") != null) {
//                    serviceGoodsPageReq.setServiceCategoryId(ClassConvertUtils.objToLong(params.get("category_id")));
//                }
//
//                if (params.get("title") != null && StringUtils.isNotBlank(params.get("title").toString())) {
//                    serviceGoodsPageReq.setTitle(params.get("title").toString());
//                }
//                Integer count = this.baseMapper.loadCount(serviceGoodsPageReq);
//                shop.setServiceGoodsTotal(count);
//            });
//
//        }, threadPoolExecutor);


        try {
            CompletableFuture.allOf(distanceProcessFuture).get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        List<NearbyShopSlimVo> collect = new ArrayList<>();
        String order = MapUtil.getStr(params, "order");
        if (StringUtils.isNotBlank(order) && order.equals("average")) {
            //评分优先
            collect = shops.stream().sorted(Comparator.comparing(NearbyShopSlimVo::getAverage).reversed()).collect(Collectors.toList());
        } else {
            //距离优先
            collect = shops.stream().sorted(Comparator.comparing(NearbyShopSlimVo::getDistance)).collect(Collectors.toList());
        }
        return collect;
    }


    private ServiceGoodsPageReq paramsMapToReq(Map<String, Object> params) {
        ServiceGoodsPageReq goodsPageReq = new ServiceGoodsPageReq();
        if (params.get("shop_id") != null) {
            goodsPageReq.setShopId(ClassConvertUtils.objToLong(params.get("shop_id").toString()));
        }
        if (params.get("shop_name") != null) {
            goodsPageReq.setShopName(params.get("shop_name").toString());
        }

        if (params.get("client") != null) {
            goodsPageReq.setClient(params.get("client").toString());
        }

        if (params.get("title") != null) {
            goodsPageReq.setTitle(params.get("title").toString());
        }

        if (params.get("verify_status") != null) {
            goodsPageReq.setVerifyStatus(ClassConvertUtils.objToInteger(params.get("verify_status")));
        }

        if (params.get("added") != null && StringUtils.isNotBlank(params.get("added").toString())) {
            goodsPageReq.setAdded(ClassConvertUtils.objToInteger(params.get("added")));
        }

        if (params.get("order_type") != null) {
            goodsPageReq.setOrderType(ClassConvertUtils.objToInteger(params.get("order_type")));
        }

        if (params.get("order_mode") != null) {
            goodsPageReq.setOrderMode(params.get("order_mode").toString());
        }

        if (params.get("city_code") != null) {
            goodsPageReq.setCityCode(params.get("city_code").toString());
        }

        if (params.get("area_code") != null) {
            goodsPageReq.setAreaCode(params.get("area_code").toString());
        }

        if (params.get("type") != null) {
            goodsPageReq.setType(params.get("type").toString());
        }

        if (params.get("limit") != null) {
            goodsPageReq.setLimit(ClassConvertUtils.objToInteger(params.get("limit")));
        }

        if (params.get("category_id") != null) {
            goodsPageReq.setServiceCategoryId(ClassConvertUtils.objToLong(params.get("category_id")));
        }

        if (params.get("group_id") != null) {
            goodsPageReq.setGroupId(ClassConvertUtils.objToLong(params.get("group_id")));
            List<ServiceGoodsGroup> children = serviceGoodsGroupService.getChildren(goodsPageReq.getGroupId());
            List<Long> collect = children.stream().map(ServiceGoodsGroup::getId).collect(Collectors.toList());
            if (collect.size() > 0) {
                goodsPageReq.setChildrenIds(collect);
            }
        }

        //联盟商家分类
        if (ObjectUtil.isNotNull(MapUtil.getLong(params, "classify_id"))) {
            goodsPageReq.setClassifyId(MapUtil.getLong(params, "classify_id"));
        }

        //是否是联盟商家
        if (ObjectUtil.isNotNull(MapUtil.getBool(params, "union_business"))) {
            goodsPageReq.setUnionBusiness(MapUtil.getBool(params, "union_business"));
        }

        return goodsPageReq;

    }


    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<ServiceGoods> page = this.page(
                new Query<ServiceGoods>().getPage(params),
                new QueryWrapper<ServiceGoods>()
        );

        return new PageUtils(page);
    }


}
